package com.dycong.common.IOutil;

import com.dycong.common.function.TryToDo;
import lombok.extern.log4j.Log4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;

/**
 * Created by Yu on 2015/4/15.
 */
@Log4j
public class IOUtil {

    private static final int BUFFER_SIZE = 1024;


    /**
     * @param
     * @return
     * @deprecated  have a bug, uses {@link IOUtils#toByteArray(InputStream)} instead
     */
    @Deprecated
    public static byte[] toByteArray(InputStream in) {
        try {
            int bufferLength;
            int length = 0;
            byte[] result = new byte[0];
            do {
                byte[] buffer = new byte[BUFFER_SIZE];
                bufferLength = in.read(buffer, 0, BUFFER_SIZE);
                if (bufferLength <= 0) {
                    break;
                }
                byte[] temp = new byte[length + bufferLength];
                if (length > 0) {
                    System.arraycopy(result, 0, temp, 0, length);
                }
                System.arraycopy(buffer, 0, temp, length, bufferLength);
                result = temp;
                length += bufferLength;
            } while (bufferLength == BUFFER_SIZE);
            return result;
        } catch (IOException e) {
            log.info("", e);
            throw new RuntimeException(e);
        }
    }

    public static String toString(InputStream in, String encoding) {
        try {
            return new String(IOUtils.toByteArray(in), encoding);
        } catch (IOException e) {
            log.info("", e);
            throw new RuntimeException(e);
        }
    }


    public static String getMd5ByFile(String fileName) {
        try (FileInputStream fis = new FileInputStream(new File(fileName))) {
            return DigestUtils.md5Hex(fis);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public static Optional<List<String>> readFromFile(String fileName) {
        try {
            return Optional.of(Files.readAllLines(Paths.get(fileName)));
        } catch (IOException e) {
            log.debug(e.toString());
            return Optional.empty();
        }
    }

    public static void writeToFile(String fileName, CharSequence... content) {
        writeToFile(fileName, Arrays.asList(content));
    }

    public static void writeToFile(String fileName, Iterable<? extends CharSequence> content) {
        try {
            Path path = Paths.get(fileName);
            if (Files.notExists(path.getParent())) {
                Files.createDirectories(path.getParent());
            }
            Files.write(path, content, Charset.forName("UTF-8"));
        } catch (IOException e) {
            log.debug("", e);
        }
    }


    public static void appendToFile(String fileName, byte[] content) {
        TryToDo.toTry(() -> {
            Path path = Paths.get(fileName);
            Files.write(path, content, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
        }).ifFailed(e -> log.error("", e));
    }

    public static void appendToFileInNewLine(String fileName, byte[] content) {
        byte newContent[] = new byte[content.length + 1];
        newContent[0] = '\n';
        System.arraycopy(content, 0, newContent, 1, content.length);
        appendToFile(fileName, newContent);
    }


//    public static void executeSystemCommand(String command,ProcessCallback stramcallback
//            ,ProcessCallback waitForcallback) throws IOException {
//        Process progress = new ProcessBuilder(command.split(" ")).redirectErrorStream(true).start();
//        if (stramcallback!=null) {
//            stramcallback.setProcess(progress);
//            stramcallback.setIs(progress.getInputStream());
//            new Thread(stramcallback).start();
//            //has allready redirecterrorins
//            //new Thread(new StreamDump(progress.getErrorStream()), "error stream").start();
//        }
//        try {
//            progress.waitFor();
//            if (waitForcallback!=null){
//                waitForcallback.setProcess(progress);
//                waitForcallback.run();
//            }
//            log.debug(progress.exitValue() == 0 ? "succeeded" : "failed");
//        } catch (InterruptedException e) {
//            log.info("interrupted");
//        }
//    }


    public static int readIntFromConsole() {
        while (true) {
            try {
                System.out.print("Please input a number: ");
                Scanner in = new Scanner(System.in); //Import java.util.Scanner for it
                return in.nextInt();
            } catch (RuntimeException e) {
                log.debug(e.toString());
                System.out.println("Input number failed, try again.");
            }
        }
    }

    public static byte[] serialize(Object object) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Object deserialize(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

